package com.mhh.selary.backend.intercepter;

import com.mhh.sdk.beans.LoginUserContext;
import com.mhh.sdk.beans.annotation.GrayList;
import com.mhh.sdk.beans.annotation.WhiteList;
import com.mhh.sdk.beans.dto.LoginUser;
import com.mhh.sdk.utils.beans.SpringUtils;
import com.mhh.selary.backend.api.user.ISelaryUserAccountService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * @author mhh
 * @date 2020-11-19 15:07:02
 */
@Slf4j
@Component
public class LoginIntercepter implements HandlerInterceptor {

    private static final String HTTP_METHOD_OPTIONS = "OPTIONS";

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        log.info("LoginIntercepter preHandle ------------------------------{}", request.getRequestURI());

        // 如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }

        //跨域options请求还是要放一条生路的
        if (HTTP_METHOD_OPTIONS.equalsIgnoreCase(request.getMethod())) {
            return true;
        }

        Method method = this.handlerMethod(handler);
        //白名单是政治正确，直接放过
        if (this.isWhiteList(method)) {
            return true;
        }

        // 只有token了，才会有当前登录的用户，才会保存到当前线程里面
        LoginUserContext.set(this.verifyRequest(request));
        return true;
    }

    /**
     * 验证请求合法性
     *
     * @param request
     * @return
     */
    private LoginUser verifyRequest(HttpServletRequest request) {
        String token = request.getHeader("X-Token");
        ISelaryUserAccountService userAccountService = SpringUtils.getBean(ISelaryUserAccountService.class);
        return userAccountService.loginVerify(token);
    }

    private Method handlerMethod(Object handler) {
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        return handlerMethod.getMethod();
    }

    /**
     * 判断是否白名单方法
     *
     * @param method
     * @return
     */
    private boolean isWhiteList(Method method) {
        //检查方法上是否有WhiteList注释
        if (method.isAnnotationPresent(WhiteList.class)) {
            WhiteList whiteList = method.getAnnotation(WhiteList.class);
            return whiteList.required();
        }
        return false;
    }

    /**
     * 判断是否灰名单方法
     *
     * @param method
     * @return
     */
    private boolean isGrayList(Method method) {
        //检查方法上是否有GrayList注释
        if (method.isAnnotationPresent(GrayList.class)) {
            GrayList grayList = method.getAnnotation(GrayList.class);
            return grayList.required();
        }
        return false;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        LoginUserContext.clear();
    }
}
